import routers, { LOGIN_PATH, RouteItem } from "@/config/router.config";
import { userStore } from "@/store";
import { useAtom } from "jotai";
import React from "react";
import { Navigate, Outlet, Route, useLocation } from "react-router-dom";
import * as service from '@/api/auth'

export interface AppMenu {
  key: string,
  path: string,
  router: RouteItem,
  text?: string,
  icon?: JSX.Element,
  children: AppMenu[],
  parent?: AppMenu,
}

export interface AppCrumb {
  name?: string,
  path: string,
}

// 路径头加反斜杠
function slashPath(source: string){
  return source[0] === '/' ? source: `/${source}`
}

// 将路由转换为菜单（路径从相对路径转换为绝对路径）
function generateMenu(router:RouteItem, parent: AppMenu|undefined=undefined): AppMenu{
  const parentPath = parent ? slashPath(parent.path) : ''
  const path = slashPath(router.path)
  const menu: AppMenu = {
    key: router.name,
    path: `${parentPath}${path}`,
    router: router,
    text: router.meta?.title,
    icon: router.meta?.icon,
    parent: parent,
    children: []
  }
  if(router.children){
    router.children.forEach(child=>{
      !child.hidden && menu.children.push(generateMenu(child, menu))
    })
  }
  return menu;
}

// 将路由转换为菜单
export function generateMenus(source: RouteItem[]): AppMenu[]{
  return source.filter(item=>!item.hidden).map(item=>generateMenu(item))
}

// 根据路径找到菜单项
export function getMenuByPath(source: AppMenu[], path: string): AppMenu|undefined {
  let result = source.find(item=>item.path === path)
  if(result){return result}
  for(const item of source){
    result = getMenuByPath(item.children, path)
    if(result){return result}
  }
}

// 根据标识找到菜单项
export function getMenuByKey(source: AppMenu[], key: string): AppMenu|undefined {
  let result = source.find(item=>item.key === key)
  if(result){return result}
  for(const item of source){
    result = getMenuByKey(item.children, key)
    if(result){return result}
  }
}

// 根据菜单项形成面包屑
export function generateCrumbs(source: AppMenu|undefined): AppCrumb[]{
  const result: AppCrumb[] = []
  while(source){
    result.push({
      name: source.text,
      path: source.path
    })
    source = source.parent
  }
  return result.reverse()
}


export function renderRouter(item: RouteItem){
  return (
    <Route key={item.name} path={item.path} element={
      <React.Suspense fallback={<></>}>
        {
          item.children ? <Outlet/> : (item.component && <item.component/>)
        }
      </React.Suspense>
    }>
      {
        item.children && item.children.map(child => renderRouter(child))
      }
      {
        item.redirect && <Route path="" element={<Navigate to={item.redirect}/>}/>
      }
    </Route>
  )
}

function hasPermission(route: RouteItem, role:string): boolean{
  const permission = route.meta && route.meta.permission
  if(!permission){
    // 如果没有配置则开放访问
    return true
  }
  // 简单的判断：服务端role == 客户端的permission
  return permission.find(item=>item===role)!=undefined
}

/*
  判断权限
  逻辑：按层级从上往下判断
*/
function checkPermission(source: RouteItem[], path: string, role:string){
  path = path.replace(/^\/+/,"").replace(/\/+$/, '');  // 去除路径的前后斜杠，例如（ /abc/def/ => abc/def )
  if(path===''){
    //首页不判断权限
    return true
  }
  const ar = path.split('/')
  let leafRouters = source
  for(let i=0;i<ar.length;i++){
    const leaf = leafRouters.find(item=>item.path===ar[i])
    if(!leaf || !hasPermission(leaf, role)){
      return false
    }
    if(i===ar.length-1){
      // 终节点找到，且已经通过权限验证（优先上层的，然后自己的）
      return true
    } else {
      if(!leaf.children){
        break
      }
      leafRouters = leaf.children
    }
  }
  return false
}

// 根据用户角色筛选路由
function filterRouters(source: RouteItem[], role: string): RouteItem[] {
  const result: RouteItem[] = []
  source.forEach(item => {
    if(hasPermission(item, role)){
      const cloneItem = Object.assign({}, item)
      item.children && (cloneItem.children = filterRouters(item.children, role))
      result.push(cloneItem)
    }
  })
  return result
}


export function RequireAuth(props: {children: JSX.Element}){
  const [user, setUser] = useAtom(userStore)
  const location = useLocation()
  const [loading, setLoading] = React.useState(true)
  React.useEffect(()=>{
    if(!user.info && window.localStorage.getItem("access-token")){
      // 如果会话不存在 且 本地存储Token存在 (浏览器刷新页面触发)
      (async () => {
        // 接口读取用户信息
        const {data} = await service.userinfo()
        user.info = data
        user.routers = filterRouters(routers, data.role)
        // 用户信息写入会话
        setUser(user)
        setLoading(false)
      })()  
    } else {
      setLoading(false)
    }
  }, [user.info])
  if(user.info && user.routers){
    // 如果会话存在
    // 如果有权限就跳转业务页面，否则跳转首页（也可以添加一个403页面跳转）
    return checkPermission(user.routers, location.pathname, user.info.role) ? props.children : <Navigate to="/"/>
  }
  else if(loading){
    // 显示一个loading页面
    return <div></div>
  }
  else {
    // token不存在，则跳转登录页面
    return <Navigate to={LOGIN_PATH}/>
  }
}